package com.ledtechdesign.service.api;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.digester.Digester;
import org.apache.commons.digester.ObjectParamRule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ledtechdesign.beans.Item;
import com.ledtechdesign.beans.api.IAccountInfo;
import com.ledtechdesign.beans.api.IMeetingInfo;
import com.ledtechdesign.beans.api.IMeetingInfoDescriptor;
import com.ledtechdesign.beans.api.INode;
import com.ledtechdesign.beans.api.IRepository;
import com.ledtechdesign.beans.api.pojo.AFCSNode;
import com.ledtechdesign.beans.api.pojo.AccountInfo;
import com.ledtechdesign.beans.api.pojo.MeetingInfo;
import com.ledtechdesign.beans.api.pojo.MeetingInfoDescriptor;
import com.ledtechdesign.beans.api.pojo.Repository;
import com.ledtechdesign.service.ContainerType;
import com.ledtechdesign.service.IAFCSService;

public class AFCSAPIDigesterResult implements IAFCSServiceResult {
	// this is the default format JCR is using, and as long as we get
	// JCR compliant repository xml from Adobe, this should be fine.
	public static String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
	// Fri Feb 27 22:08:52 EST 2009
	Log logger = LogFactory.getLog(this.getClass());
	String typesDate[] = { "java.lang.Object", "java.util.Date" };
	String typesString[] = { "java.lang.Object", "java.lang.Object" };

	public IAccountInfo createAccountInfo(InputStream is) throws Exception {

		Digester digester = new Digester();
		digester.setValidating(false);

		// TODO what is this : 011 10:00:00.00

		digester.addObjectCreate("result/account-info", AccountInfo.class);
		digester.addBeanPropertySetter("result/account-info/id", "id");
		digester.addBeanPropertySetter("result/account-info/owner", "owner");
		digester.addBeanPropertySetter("result/account-info/user-limit",
				"userLimit");
		digester.addBeanPropertySetter("result/account-info/total-time-limit",
				"totalTimeLimit");
		digester.addBeanPropertySetter(
				"result/account-info/total-message-limit", "totalMessageLimit");
		digester.addBeanPropertySetter("result/account-info/user-count",
				"userCount");
		digester.addBeanPropertySetter("result/account-info/bandwidth-limit",
				"bandwidthLimit");
		digester.addBeanPropertySetter("result/account-info/total-bytes-up",
				"totalBytesUp");
		digester.addBeanPropertySetter(
				"result/account-info/reported-total-bytes-up",
				"reportedTotalBytesUp");
		digester.addBeanPropertySetter("result/account-info/total-bytes-down",
				"totalBytesDown");
		digester.addBeanPropertySetter(
				"result/account-info/reported-total-bytes-down",
				"reportedTotalBytesDown");
		digester.addBeanPropertySetter("result/account-info/session-limit",
				"sessionLimit");

		// TODO need to split as soon as I get approved format from afcs folks.
		digester.addCallMethod("result/account-info/active-FMS-instances",
				"addActiveFMSInstance", 1);
		digester.addCallParam("result/account-info/active-FMS-instances", 0);

		digester.addBeanPropertySetter("result/account-info/total-time",
				"totalTime");
		digester.addBeanPropertySetter(
				"result/account-info/reported-total-time", "reportedTotalTime");
		digester.addBeanPropertySetter("result/account-info/total-messages",
				"totalMessages");
		digester.addBeanPropertySetter(
				"result/account-info/reported-total-messages",
				"reportedTotalMessages");

		digester.addCallMethod("result/account-info/date-created",
				"convertStringToDate", 2);
		digester.addCallParam("result/account-info/date-created", 0);
		digester.addRule("result/account-info/date-created",
				new ObjectParamRule(1, "created"));

		digester.addCallMethod("result/account-info/date-expired",
				"convertStringToDate", 2);
		digester.addCallParam("result/account-info/date-expired", 0);
		digester.addRule("result/account-info/date-expired",
				new ObjectParamRule(1, "expired"));

		digester.addCallMethod("result/account-info/last-report-date",
				"convertStringToDate", 2);
		digester.addCallParam("result/account-info/last-report-date", 0);
		digester.addRule("result/account-info/last-report-date",
				new ObjectParamRule(1, "lastReportedDate"));

		IAccountInfo ai;
		try {
			// repository = Utils.parseXML(data);
			ai = (IAccountInfo) digester.parse(is);
			ai.print();
			// logger.debug(Utils.printXML(repository));
		} catch (Exception e) {
			throw new Exception("bad-response", e);
		}
		return ai;
	}

	public List<Item> createItemsList(InputStream data, ContainerType type)
			throws Exception {

		List<Item> items = new ArrayList<Item>();
		IRepository r;
		try {
			// repository = Utils.parseXML(data);
			r = (IRepository) this.createRepository(data);
			r.print();

			List<INode> ns = r.getChildren();

			for (Iterator<INode> iterator = ns.iterator(); iterator.hasNext();) {
				INode node = iterator.next();
				String name = node.getName();
				String desc = null;
				Date created = null;

				Map<String, Object> node_properties = node.getProperties();
				Iterator<Map.Entry<String, Object>> it = node_properties
						.entrySet().iterator();
				while (it.hasNext()) {
					Map.Entry<String, Object> pairs = it.next();

					if (pairs.getKey().equals("cr:description")) {
						desc = ((String) pairs.getValue()).trim();
					} else if (pairs.getKey().equals("jcr:created")) {
						String raw = ((String) pairs.getValue()).trim();
						created = new java.text.SimpleDateFormat(
								ISO8601_DATE_FORMAT).parse(raw);
					}
					this.logger
							.debug(pairs.getKey() + " = " + pairs.getValue());
				}

				Item a = new Item(name, desc, created,
						type == IAFCSService.TEMPLATE_ITEMS);
				items.add(a);
			}
			// logger.debug(Utils.printXML(repository));
		} catch (Exception e) {
			throw new Exception("bad-response", e);
		}
		return items;
	}

	public IMeetingInfo createMeetingInfo(InputStream is) throws Exception {

		Digester digester = new Digester();
		digester.setValidating(false);

		// String pattern = MEET_INFO_DATE_FORMAT;
		// Locale locale = Locale.getDefault();
		// DateLocaleConverter converter = new DateLocaleConverter(locale,
		// pattern);
		// converter.setLenient(true);
		// ConvertUtils.register(converter, java.util.Date.class);

		digester.addObjectCreate("result/meeting-info", MeetingInfo.class);
		digester.addBeanPropertySetter("result/meeting-info/name", "name");
		digester.addBeanPropertySetter(
				"result/meeting-info/meeting-session-id", "sessionID");
		digester.addBeanPropertySetter("result/meeting-info/fms", "fms");
		digester.addBeanPropertySetter("result/meeting-info/host", "host");
		digester.addBeanPropertySetter("result/meeting-info/is-connected",
				"connected");
		digester.addBeanPropertySetter("result/meeting-info/user-count",
				"userCount");
		digester.addBeanPropertySetter("result/meeting-info/account-id",
				"accountId");
		digester.addBeanPropertySetter("result/meeting-info/account-ident",
				"accountIdent");
		digester.addBeanPropertySetter("result/meeting-info/total-bytes-up",
				"totalBytesUp");
		digester.addBeanPropertySetter("result/meeting-info/total-bytes-down",
				"totalBytesDown");
		digester.addBeanPropertySetter("result/meeting-info/total-messages",
				"totalBytesMessages");
		digester.addBeanPropertySetter("result/meeting-info/peak-users",
				"peakUsers");

		digester.addCallMethod("result/meeting-info/date-created",
				"convertStringToDate", 2);
		digester.addCallParam("result/meeting-info/date-created", 0);
		digester.addRule("result/meeting-info/date-created",
				new ObjectParamRule(1, "created"));

		digester.addCallMethod("result/meeting-info/date-started",
				"convertStringToDate", 2);
		digester.addCallParam("result/meeting-info/date-started", 0);
		digester.addRule("result/meeting-info/date-started",
				new ObjectParamRule(1, "started"));

		digester.addCallMethod("result/meeting-info/date-ended",
				"convertStringToDate", 2);
		digester.addCallParam("result/meeting-info/date-ended", 0);
		digester.addRule("result/meeting-info/date-ended", new ObjectParamRule(
				1, "ended"));

		digester.addCallMethod("result/meeting-info/date-expired",
				"convertStringToDate", 2);
		digester.addCallParam("result/meeting-info/date-expired", 0);
		digester.addRule("result/meeting-info/date-expired",
				new ObjectParamRule(1, "expired"));

		// digester.addBeanPropertySetter("result/meeting-info/date-created","created");
		// digester.addBeanPropertySetter("result/meeting-info/date-started","started");
		// digester.addBeanPropertySetter("result/meeting-info/date-ended","ended");
		// digester.addBeanPropertySetter("result/meeting-info/date-expired","expired");
		IMeetingInfo mi;
		try {
			// repository = Utils.parseXML(data);
			mi = (IMeetingInfo) digester.parse(is);
			mi.print();
			// logger.debug(Utils.printXML(repository));
		} catch (Exception e) {
			throw new Exception("bad-response", e);
		}
		return mi;
	}

	public IMeetingInfoDescriptor createMeetingInfoDescriptor(InputStream d)
			throws Exception {
		Digester digester = new Digester();
		digester.setValidating(false);
		digester.addObjectCreate("meeting-info", MeetingInfoDescriptor.class);
		digester.addSetProperties("meeting-info/baseURL", "href", "baseURL");
		digester.addSetProperties("meeting-info/accountPath", "href",
				"accountPath");
		digester.addSetProperties("meeting-info/room", "instance",
				"roomInstanceURL");
		digester.addSetProperties("meeting-info/fmsURL", "href", "fmsURL");
		digester
				.addSetProperties("meeting-info/ticketURL", "href", "ticketURL");

		return (IMeetingInfoDescriptor) digester.parse(d);
	}

	public IRepository createRepository(InputStream data) throws Exception {

		Digester digester = new Digester();
		digester.setValidating(false);

		// if (Utils.DEBUG) logger.debug(data);

		digester.addObjectCreate("repository", Repository.class);

		digester.addSetProperties("repository/children", "count",
				"childrenCount");
		digester.addSetProperties("repository/children", "total",
				"totalChildren");
		digester.addSetProperties("repository", "href", "href");
		digester.addObjectCreate("repository/node", AFCSNode.class);
		digester.addSetProperties("repository/node", "href", "href");
		digester.addSetProperties("repository/node", "type", "type");
		digester.addBeanPropertySetter("repository/node/name");
		digester.addCallMethod("repository/node/properties/property",
				"addProperty", 2);
		digester.addCallParam("repository/node/properties/property", 0, "name");
		digester.addCallParam("repository/node/properties/property/value", 1);
		digester.addSetNext("repository/node", "setTopNode");
		digester.addObjectCreate("repository/children/node", AFCSNode.class);
		digester.addSetProperties("repository/children/node", "href", "href");
		digester.addSetProperties("repository/children/node", "type", "type");
		digester.addBeanPropertySetter("repository/children/node/name");
		digester.addCallMethod("repository/children/node/properties/property",
				"addProperty", 2);
		digester.addCallParam("repository/children/node/properties/property",
				0, "name");
		digester.addCallParam(
				"repository/children/node/properties/property/value", 1);

		digester.addSetNext("repository/children/node", "addChildren");

		IRepository r;

		List<Item> items = new ArrayList<Item>();

		try {
			// repository = Utils.parseXML(data);
			r = (IRepository) digester.parse(data);
			r.print();
			// logger.debug(Utils.printXML(repository));
		} catch (Exception e) {
			throw new Exception("bad-response", e);
		}
		return r;
	}

	public IRepository delete(InputStream i) throws Exception {

		Digester digester = new Digester();
		digester.setValidating(false);

		digester.addObjectCreate("repository", Repository.class);
		digester.addSetProperties("repository/children", "count",
				"childrenCount");
		digester.addSetProperties("repository/children", "total",
				"totalChildren");
		digester.addSetProperties("repository", "href", "href");
		digester.addObjectCreate("repository/node", AFCSNode.class);
		digester.addSetProperties("repository/node", "href", "href");
		digester.addSetProperties("repository/node", "type", "type");
		digester.addBeanPropertySetter("repository/node/name");
		digester.addCallMethod("repository/node/properties/property",
				"addProperty", 2);
		digester.addCallParam("repository/node/properties/property", 0, "name");
		digester.addCallParam("repository/node/properties/property/value", 1);
		digester.addSetNext("repository/node", "setTopNode");
		digester.addObjectCreate("repository/children/node", AFCSNode.class);
		digester.addSetProperties("repository/children/node", "href", "href");
		digester.addSetProperties("repository/children/node", "type", "type");
		digester.addBeanPropertySetter("repository/children/node/name");
		digester.addCallMethod("repository/children/node/properties/property",
				"addProperty", 2);
		digester.addCallParam("repository/children/node/properties/property",
				0, "name");
		digester.addCallParam(
				"repository/children/node/properties/property/value", 1);
		digester.addSetNext("repository/children/node", "addChildren");

		IRepository r;

		try {
			// repository = Utils.parseXML(data);
			r = (IRepository) digester.parse(i);
			r.print();
			// logger.debug(Utils.printXML(repository));
		} catch (Exception e) {
			throw new Exception("bad-response", e);
		}

		return r;
	}

}
